<template>
  <view>
    <!-- 搜索框 -->
    <view class="header">
      <!-- 搜索栏 -->
      <luyj-tree-search
        v-if="searchIf"
        :backgroundColor="searchBackgroundColor"
        :inputBackgroundColor="searchInputBackgroundColor"
        :radius="searchRadius"
        :iconColor="searchIconColor"
        :placeholder="searchPlaceholder"
        :placeholderStyle="searchPlaceholderStyle"
        :maxlength="searchMaxlength"
        :clearable="searchClearable"
        @confirm="confirmSearch"
      ></luyj-tree-search>
      <!-- 面包屑导航 -->
      <luyj-tree-navigation
        :slabel="props.label"
        @inF="navigationInt"
        @clickItem="backTree"
      >
      </luyj-tree-navigation>
      <!-- 面包屑导航 -->
    </view>
    <!-- 列表 -->
    <view>
      <view
        class="container-list"
        :style="{
          'padding-bottom': isCheck ? '160rpx' : 0,
          'padding-top': searchIf ? '200rpx' : '90rpx',
        }"
      >
        <luyj-tree-item
          v-for="(item, index) in tree"
          :key="index"
          :item="item"
          :isCheck="isCheck"
          :checkActiveColor="checkActiveColor"
          :checkNoneColor="checkNoneColor"
          :multiple="props.multiple"
          :checked="isChecked(item)"
          :nodes="props.nodes"
          :comparison="comparison"
          @clickItem="toChildren"
          @change="checkbox($event, item, index)"
        >
          <template slot="body">
            <slot v-bind:item="item" v-bind:slotObj="slotObj">
              <view class="word text-cut">{{ item[props.label] }}</view>
            </slot>
          </template>
        </luyj-tree-item>
      </view>
    </view>

    <!-- 确定按钮 -->
    <view v-if="isCheck" class="btn box_sizing">
      <button class="sureBtn" type="primary" @click="backConfirm">确认</button>
    </view>
  </view>
</template>

<script>
import luyjTreeNavigation from "../luyj-tree-navigation/luyj-tree-navigation.vue";
import luyjTreeSearch from "../luyj-tree-search/luyj-tree-search.vue";
import luyjTreeItem from "../luyj-tree-item/luyj-tree-item.vue";

/**
 * luyj-tree 无限树形结构树、支持搜索选择。
 * @description  无限树形结构组件。支持搜索、选择(包括单选、多选)。面包屑类型导航。原插件地址：https://ext.dcloud.net.cn/plugin?id=2423。
 * @tutorial url https://ext.dcloud.net.cn/plugin?name=luyj-tree
 * @property {Boolean} searchIf 是否开启搜索 （默认值true）
 * @property {String} searchBackgroundColor 搜索框背景色(默认#FFFFFF)
 * @property {String} searchInputBackgroundColor 搜索框的输入框背景色(默认#EEEFF0)
 * @property {Number} searchRadius 搜索框的圆角值，单位rpx（默认40）
 * @property {String} searchPlaceholder 搜索框的内容物空时提示内容
 * @property {String} searchPlaceholderStyle 搜索框的placehoder的样式
 * @property {Number} searchMaxlength 搜索框的最大输入长度 ,设置为 -1 的时候不限制最大长度
 * @property {String} searchIconColor 搜索框的图标颜色（默认#B8B8B8）
 * @property {Boolean} searchClearable 搜索框是否显示清除按钮
 * @property {Array}  trees 传入的树形结构，每个对象必须包含唯一的id值(默认值【】)
 * @property {Boolean} isCheck 是否开启选择操作（默认值false）
 * @property {Object} slotObj 传入插槽的参数（因为插槽进行了循环，不能直接引用页面的参数，需要传递）
 * @property {Array} checkList 选中列表
 * @property {Boolean} parent 当子级全选时,是否选中父级数据(prop.checkStrictly为true时生效)(默认值false)
 * @property {Array} parentList 父级列表
 * @property {String} checkActiveColor 选中时单选框的颜色 (默认#00AAFF)
 * @property {String} checkNoneColor 未选中时单选框的颜色（默认#B8B8B8)
 * @property {Object} props 参数配置。
 *  @property {String} id id列的属性名称
 * 	@param {String}  label 指定选项标签为选项对象的某个属性值(默认值:name)
 *  @param {String} children   指定选项的子选项为选项对象的某个属性名(默认值：children)
 *  @param {Boolean} multiple 值为true时为多选，为false时是单选(默认值true)
 *  @param {Boolean} checkStrictly(废弃) 需要在多选模式下才传该值，checkStrictly为false时，可让父子节点取消关联，选择任意一级选项。为true时关联子级，可以全选(默认值为false)
 *  @param {Boolean} nodes  在单选模式下，nodes为false时，可以选择任意一级选项，nodes为true时，只能选择叶子节点(默认值为true)
 * @property {Boolean} stepReload 是否“分页加载”数据
 * @property {Number} pageSize 分步加载生效时（当条数过大时，反应时间很长）
 * @return {Function} clickItem 点击导航栏事件
 * 	@value item 当前选中的item值
 *  @value 	realHasChildren 是否包含子级
 * @event {Function()} change 改变选择值时的方法
 * @event {Function()} sendValue 提交选择的方法
 * @event {Function()} backTree	选中导航栏时，返回其他层
 */
export default {
  components: {
    luyjTreeNavigation,
	luyjTreeItem,
    luyjTreeSearch,
  },
  name: "luyj-tree",
  props: {
    // 是否开启搜索
    searchIf: {
      type: Boolean,
      default: () => true,
    },
    // 搜索框背景色
    searchBackgroundColor: {
      type: String,
      default: "#FFFFFF",
    },
    // 搜索框的输入框内背景颜色
    searchInputBackgroundColor: {
      type: String,
      default: "#EEEFF0",
    },
    // 搜索框的图标的颜色
    searchIconColor: {
      type: String,
      default: "#B8B8B8",
    },
    // 搜索框的圆角值，单位rpx
    searchRadius: {
      type: Number,
      default: 40,
    },
    // 搜索框的提示placeholder内容
    searchPlaceholder: {
      type: String,
      default: "搜索",
    },
    // 搜索框的placeholder的样式
    searchPlaceholderStyle: {
      type: String,
      default: "",
    },
    // 搜索框最大输入长度 ,设置为 -1 的时候不限制最大长度
    searchMaxlength: {
      type: Number,
      default: 140,
    },
    // 搜索框是否显示清除按钮
    searchClearable: {
      type: Boolean,
      default: true,
    },
    // 传入的树形结构数据，每个对象必须包含唯一的id值
    trees: {
      type: Array,
      default: () => {
        return [];
      },
    },
    //是否开启选择操作，值为false时仅展示，无操作
    isCheck: {
      type: Boolean,
      default: () => {
        return false;
      },
    },
    // 传入插槽的其他参数
    slotObj: {
      type: Object,
      default: () => {
        return null;
      },
    },
    // 选中列表
    checkList: {
      type: Array,
      default: () => [],
    },
    // 当子级全选时,是否选中父级数据(prop.checkStrictly为true时生效)
    parent: {
      type: Boolean,
      default: () => {
        return false;
      },
    },
    // 父级列表
    parentList: {
      type: Array,
      default: () => [],
    },
    // 选中时单选框的颜色
    checkActiveColor: {
      type: String,
      default: "#00AAFF",
    },
    // 未选中时单选框的颜色
    checkNoneColor: {
      type: String,
      default: "#B8B8B8",
    },
    // 树的属性参数
    props: {
      type: Object,
      default: () => {
        return {
          id: "id",
          label: "name",
          children: "children",
          multiple: false,
          checkStrictly: false, //不关联
          nodes: false, // nodes为false时，可以选择任意一级选项；nodes为true时只能选择叶子节点
        };
      },
    },
    /**
     * 是否懒加载树的值
     */
    stepReload: {
      type: Boolean,
      default: false,
    },
    // 每次循环加载的item的数据量
    pageSize: {
      type: Number,
      default: 50,
    },
  },
  data() {
    return {
      // 导航条
      setIsre: null, // 导航条方法 - 设置是否搜索中方法
      getIsre: null, // 获取是否搜索中
      setTreeStack: null, // 导航条 - 设置导航
      concatTreeStack: null, // 导航条 - 拼接当前导航对象
      clearTreeStack: null, // 导航条- 清空导航条
      getTreeStack: null, // 导航条 - 获取导航条

      itemsLoading: false, // item是否在循环渲染中
      itemsStop: false, // 是否终止其他渲染
      tree: [], // 默认数组
      newNum: 0,
      oldNum: 0,
      allData: this.trees,
      parent_data: this.parentList || [], //选择父辈
      searchResult: [],
      newCheckList: this.checkList,
      nodePathArray: [], // 当前展示的路径
      // item名称对照表
      comparison: {
        value: this.props.id ? this.props.id : "id", // 选中值名称
        label: this.props.label ? this.props.label : "name", // 显示名称
        children: this.props.children ? this.props.children : "children", // 子集名称
      },
    };
  },
  watch: {
    // 监听数据值的变化
    trees: function (val, oldval) {
      if (val != oldval) {
        var tree_stack = this.getTreeStack();
        this.allData = val; // 重新加载所有树
        // 重新加载当前树
        if (!Array.isArray(tree_stack)) {
          this.loadTree(val);
          return;
        }
        var length = tree_stack.length;
        if (length === 0) {
          if (typeof this.getIsre === "function") {
            if (this.getIsre()) {
              return;
            }
          }
          this.loadTree(val);
        } else {
          let tempArray = val; // 存储当前值
          let children = this.props.children;
          for (var i = 0; i < length; i++) {
            var tempObject = tempArray.find((item) => {
              return tree_stack[i].Value == item.Value;
            });
            if (Boolean(tempObject)) {
              tempArray = tempObject[children];
            } else {
              // 跳转到全部
              break;
            }
            if (i == length - 1) {
              this.loadTree(tempArray);
            }
          }
        }
      }
    },
    // 树的属性对照参数
    props: {
      handler: function (val) {
        this.comparison.value = this.props.id ? this.props.id : "id";
        this.comparison.label = this.props.label ? this.props.label : "name";
        this.comparison.children = this.props.children
          ? this.props.children
          : [];
      },
      deep: true,
    },
    checkList: function (val, oldVal) {
      if (val != oldVal) {
        this.newCheckList = JSON.parse(JSON.stringify(val));
        return val;
      }
    },
  },
  created: function () {
    this.loadTree(this.trees);
  },
  // 实例被挂载后调用
  mounted() {
    let id = this.props.id;
    let children = this.props.children;
    // 关联子级的验证，暂时不使用
    // if (this.props.multiple && this.props.checkStrictly) {
    // 	if (this.newCheckList.length != 0) {
    // 		this.checkAllChoose();
    // 		return;
    // 	}
    // 	for (let i = 0; i < this.tree.length; i++) {
    // 		this.$set(this.tree[i], 'bx', 0)
    // 		this.$set(this.tree[i], 'qx', 0)
    // 	}
    // }
    // 初始化选中项
    if (!this.props.multiple && this.newCheckList.length > 0) {
      this.getNodeRoute(this.allData, this.newCheckList[0][id]);
      let arr = this.nodePathArray.reverse();
      if (arr.length == 0) {
        return;
      }

      this.concatTreeStack(arr); // 获取导航条的值
      // 加载当前列对应的数据
      var tree_stack = this.getTreeStack();
      var data = Boolean(tree_stack[tree_stack.length - 1][children])
        ? tree_stack[tree_stack.length - 1][children]
        : [];
      this.loadTree(data);
    }
  },
  methods: {
    // ========================================== 添加方法 =====================================================================
    /** 当前选项是否选中
     * @param {Object} item
     */
    isChecked(item) {
      if (Array.isArray(this.newCheckList)) {
        let id = this.props.id;
        let temp = this.newCheckList.find((chcked) => {
          return chcked[id] == item.id;
        });
        return Boolean(temp);
      }
      return false;
    },
    // =========================================== 初始化方法 ===================================================================
    /** 初始化导航条的方法
     * @param {Object} e
     */
    navigationInt: function (e) {
      this.setIsre = e.setIsre;
      this.getIsre = e.getIsre;
      this.concatTreeStack = e.concatTreeStack;
      this.pushTreeStack = e.pushTreeStack;
      this.clearTreeStack = e.clearTreeStack;
      this.getTreeStack = e.getTreeStack;
    },
    // =========================================== 监听事件 =====================================================================
    /** 选中当前的值
     * @param {Object} e
     * @param {Object} item 当前项
     * @param {Object} index 低昂去索引
     */
    checkbox(e, item, index) {
      var func = this.props.multiple ? this.checkboxChange : this.radioChange;
      func(e, item, index); // 执行选择操作
    },
    /**单选
     * @param {Object} e 点击事件
     * @param {Object} item 当前项的值
     * @param {Object} index 索引
     */
    radioChange: function (e, item, index) {
      var that = this;
      if (e.detail.value) {
        // 选中当前对象
        that.newCheckList = [];
        that.newCheckList.push(that.tree[index]);
      } else {
        // 移除其他对象
        var nIndex = that.newCheckList.indexOf(item);
        that.newCheckList.splice(nIndex, 1);
      }
      that.$emit("change", that.newCheckList);
    },
    /**异步检查复选框值的改变
     * @param {Object} item
     * @param {Object} index
     * @param {Object} bx
     * @param {Object} qx
     */
    async checkboxChange(e, item, index, bx, qx) {
      let that = this;
      let findIdex = that.newCheckList.indexOf(item);
      if (e.detail.value) {
        // 点击选中
        if (findIdex == -1) {
          that.newCheckList.push(that.tree[index]);
        }
      } else {
        // 点击不选
        that.newCheckList.splice(findIdex, 1);
      }
      that.$emit("change", that.newCheckList);

      // if (findIdex > -1) { //反选
      // 	if (that.props.checkStrictly) { //关联子级
      // 		if (item[props.hasChilren]) { //用户
      // 			that.newCheckList.splice(findIdex, 1)
      // 		} else { //非用户，取消所有下一级
      // 			if (Boolean(item[props.children])) {
      // 				that.getIdBydelete(item[props.children]);
      // 			}
      // 		}
      // 	} else {
      // 		that.newCheckList.splice(findIdex, 1)
      // 	}
      // } else { //选中
      // 	if (!item[this.props.hasChilren] && that.props.checkStrictly) { //选中下一级
      // 		if (qx || bx) { //取消下级
      // 			if (Boolean(item[props.children])) {
      // 				await that.getIdBydelete(item[props.children]);
      // 			}
      // 			item.qx = 0;
      // 			item.bx = 0;
      // 		} else {
      // 			item.qx = 1;
      // 			item.bx = 0;
      // 			if (Boolean(item[props.children])) {
      // 				await that.chooseChild(item[props.children], item[this.props.id]);
      // 			}
      // 		}
      // 		that.$emit('change', that.newCheckList);
      // 		// that.$forceUpdate()
      // 		return;
      // 	}
      // 	// if(item[this.props.hasChilren]&&this.props.checkStrictly) this.getNodeRoute(this.allData,item[this.props.id]);
      // 	that.newCheckList.push({
      // 		...item
      // 	});
      // }
      // that.$emit('change', that.newCheckList)
    },
    // 取消下一级的选中
    getIdBydelete(arr) {
      arr.forEach((e) => {
        if (true) {
          for (var i = 0; i < this.newCheckList.length; i++) {
            // 包含下一级
            if (e[this.props.id] == this.newCheckList[i][this.props.id]) {
              this.newCheckList.splice(i, 1);
              break;
            }
          }
        }
        if (false) {
          // 不包含下一级
          if (Boolean(item[props.children])) {
            this.getIdBydelete(e[props.children]);
          }
        }
      });
    },
    // 关联下一级,选中
    chooseChild(arr, pid) {
      let that = this;
      for (var i = 0, len = arr.length; i < len; i++) {
        let item = arr[i];
        if (true) {
          // 包含下一级
          that.newCheckList.push({
            ...item,
            tree_stackId: pid,
          });
        }
        if (false) {
          // 不包含下一级
          // !item[that.props.hasChilren]
          if (Boolean(item[props.children])) {
            this.chooseChild(item[props.children], item[this.props.id]);
          }
        }
      }
    },

    /**
     * @param {Array} tree 目标树
     * @param {Object} targetId 为目标节点id
     */
    getNodeRoute(tree, targetId) {
      let children = this.props.children;
      let id = this.props.id;
      for (let index = 0; index < tree.length; index++) {
        if (Boolean(tree[index][children])) {
          if (tree[index][children]) {
            let endRecursiveLoop = this.getNodeRoute(
              tree[index][children],
              targetId
            );
            if (endRecursiveLoop) {
              this.nodePathArray.push(tree[index]);
              return true;
            }
          }
        }
        if (tree[index][id] === targetId) {
          return true;
        }
      }
    },

    /**跳转到子级
     * @param {Object} item 选中的项
     * @param {Boolean} realHasChildren 是否包含子级
     */
    toChildren(item, realHasChildren) {
      this.$emit("clickItem", item, realHasChildren); // 点击导航栏事件
      // 不包含子级,不执行任何操作
      if (!realHasChildren) {
        return;
      }
      // 点击跳转下一级
      let id = this.props.id;
      let children = this.props.children; // 子级名称

      // 将当前item加入到导航列表
      if (item[children].length > 0) {
        this.loadTree(item[children]);
        this.pushTreeStack(item); // 添加导航
      }
      // 关联数据 - 暂时不使用
      // if (this.props.checkStrictly) {
      // 	this.checkAllChoose();
      // }
    },
    /** 搜索提交方法
     * @param {Object} e
     */
    confirmSearch(e) {
      var val = e.detail.value;
      this.searchResult = [];
      // 查找
      uni.showLoading({
        title: "正在查找",
      });
      this.search(this.allData, val);
      // 返回搜索结果
      uni.hideLoading();
      this.setIsre(true); // 设置导航条为搜索状态
      this.clearTreeStack(); // 清空导航条
      this.loadTree(this.searchResult);
    },
    /**搜索方法
     * @param {Object} data 搜索数据
     * @param {Object} keyword 搜索关键字
     */
    search(data, keyword) {
      var that = this;
      let children = that.props.children;
      for (var i = 0, len = data.length; i < len; i++) {
        // try-catch(try-catch) - 没有label列，跳过继续执行
        try {
          if (data[i][that.props.label].indexOf(keyword) >= 0) {
            that.searchResult.push(data[i]);
          }
          if (Boolean(data[i][children])) {
            if (data[i][children].length > 0) {
              that.search(data[i][children], keyword);
            }
          }
        } catch (e) {
          console.warn(e);
        }
      }
    },
    /**
     * 检查所有的选项
     */
    checkAllChoose() {
      let o = false,
        t = true;
      this.tree.forEach((e, i) => {
        if (true) {
          // 包含下一级 !e[this.props.hasChilren]
          e.qx = o;
          e.bx = o;
          let num2 = this.computAllNumber(e[props.children]);
          // console.log(this.newNum,this.oldNum)
          if (this.newNum != 0 && this.oldNum != 0) {
            if (this.newNum == this.oldNum) {
              e.qx = t;
              e.bx = o;
            } else {
              e.qx = o;
              e.bx = t;
            }
          }
          if (this.newNum != 0 && this.oldNum == 0) {
            this.$set(this.tree[i], "bx", o);
            this.$set(this.tree[i], "qx", o);
          }
          // this.$forceUpdate()
          this.newNum = 0;
          this.oldNum = 0;
        }
      });
    },

    // 选中所选值
    computAllNumber(arr) {
      console.log("选中所选值");
      // for (let j = 0; j < arr.length; j++) {
      // 	var e = arr[j];
      // 	// if (arr[j][that.props.hasChilren]) {
      // 		this.newNum++;
      // 	// }
      // 	this.checkSum(e.id)
      // 	if (!e[that.props.hasChilren]) {
      // 		this.computAllNumber(e[props.children])
      // 	}
      // }
    },

    // 选中事件累计
    checkSum(id) {
      for (let i = 0; i < this.newCheckList.length; i++) {
        if (id == this.newCheckList[i].id) {
          this.oldNum++;
          break;
        }
      }
    },

    /** 返回到其他树层
     * @param {Object} item 当前item值
     * @param {Object} index 返回到其他索引
     */
    backTree(item, index) {
      this.$emit("backTree", item, index);
      let that = this;
      if (index == -1) {
        // 全部
        that.loadTree(that.allData);
      } else if (index == -2) {
        // 搜索
        that.loadTree(that.searchResult); // 搜索结果
      } else {
        // 其他层级
        that.loadTree(item[that.props.children]); // tree的其他层级
      }
      // 关联数据
      // if (this.props.checkStrictly) {
      // 	this.checkAllChoose();
      // }
    },
    /**
     * 点击确认按钮执行事件
     */
    backConfirm() {
      this.$emit("sendValue", this.newCheckList, "back");
    },
    // ======================================== 公共方法 ===============================================================
    /**加载Tree值
     * @param {Array} datas 待复制的数组
     * @param {Number} start 起始位置
     * @description 加载tree值。当数据量大时，子项加载时间很长。可以多次渲染加载
     */
    loadTree: function (datas, start = 0) {
      let that = this;
      if (!this.stepReload) {
        // 不进行多次渲染加载
        that.tree = datas;
      } else {
        // datas为null, 不进行渲染
        if (!Array.isArray(datas)) {
          that.tree = datas;
          return;
        } else if (datas.length === 0) {
          that.tree = datas;
          return;
        }
        // 进行多次渲染加载
        if (start === 0) {
          // 终止其他渲染
          if (that.itemsLoading) {
            that.itemsStop = true; //终止其他Item渲染
          }
          // 首次加载提醒
          uni.showLoading();
          that.tree = [];
          that.itemsLoading = true;
        }
        var length = datas.length;
        var end = Math.min(start + that.pageSize, length);
        var tempArray = datas.slice(start, end);
        that.tree = that.tree.concat(tempArray);
        that.$nextTick(function () {
          if (start == 0) {
            uni.hideLoading();
            that.itemsStop = false;
          }
          if (end < length && !that.itemsStop) {
            that.loadTree(datas, end);
          } else {
            that.itemsLoading = false;
          }
        });
      }
    },
    // =================================================================================================================
  },
};
</script>
<style lang="scss" scoped>
@import "luyj-tree.scss";
@import "icon.css";
</style>
